package chat;

import javax.sound.sampled.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

public class VoiceChatManager {
    public static final int VOICE_PORT = 52000;
    private static final int SAMPLE_RATE = 8000;
    private static final int SAMPLE_SIZE = 16;
    private static final int CHANNELS = 1;
    private static final boolean SIGNED = true;
    private static final boolean BIG_ENDIAN = false;
    // private static String currentUsername; // 添加这行

    private static DatagramSocket voiceSocket;
    private static AudioFormat audioFormat;
    private static TargetDataLine microphone;
    private static SourceDataLine speakers;

    // 当前语音会话参与者 (用户名 -> 端口)
    private static Map<String, Integer> currentVoiceParticipants = new ConcurrentHashMap<>();
    // 会议房间映射 (房间ID -> 参与者列表)
    private static Map<String, Set<String>> conferenceRooms = new ConcurrentHashMap<>();
    // 用户信息映射 (用户名 -> UserVoiceInfo)
    private static Map<String, UserVoiceInfo> userInfoMap = new ConcurrentHashMap<>();

    private static final int BUFFER_SIZE = 1024;

    static class UserVoiceInfo {
        String ipAddress;
        int voicePort;

        public UserVoiceInfo(String ipAddress, int voicePort) {
            this.ipAddress = ipAddress;
            this.voicePort = voicePort;
        }
    }

    // 初始化语音系统
    private static boolean initialized = false;
    // 在VoiceChatManager中添加：
    public static boolean isInitialized() {
        return initialized;
    }

    public static void initialize(String username) {
        if (initialized) {
            System.out.println("语音系统已初始化，跳过重复初始化");
            // 即使跳过初始化，也要确保IP信息是最新的
            try {
                String localIP = InetAddress.getLocalHost().getHostAddress();
                int actualPort = voiceSocket.getLocalPort();
                updateUserIP(username, localIP, actualPort);
                System.out.println("更新本地语音信息: " + username + " -> " + localIP + ":" + actualPort);
            } catch (Exception e) {
                System.err.println("更新本地语音信息失败: " + e.getMessage());
            }
            return;
        }


        try {
            audioFormat = new AudioFormat(SAMPLE_RATE, SAMPLE_SIZE, CHANNELS, SIGNED, BIG_ENDIAN);

            if (!checkAudioDevices()) {
                System.err.println("音频设备检查失败");
                return;
            }

            voiceSocket = new DatagramSocket(0);
            voiceSocket.setSoTimeout(1000);

            int actualPort = voiceSocket.getLocalPort();
            System.out.println(username + " 语音系统初始化完成，监听端口: " + actualPort);

            updateUserIP(username, InetAddress.getLocalHost().getHostAddress(), actualPort);

            new Thread(() -> receiveVoice()).start();
            initialized = true;
        } catch (Exception e) {
            System.err.println("语音系统初始化失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 新增音频设备检查方法
    private static boolean checkAudioDevices() {
        try {
            DataLine.Info micInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
            if (!AudioSystem.isLineSupported(micInfo)) {
                System.err.println("麦克风不支持指定的音频格式");
                return false;
            }

            DataLine.Info speakerInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
            if (!AudioSystem.isLineSupported(speakerInfo)) {
                System.err.println("扬声器不支持指定的音频格式");
                return false;
            }

            return true;
        } catch (Exception e) {
            System.err.println("音频设备检查异常: " + e.getMessage());
            return false;
        }
    }

    public static int getVoicePort() {
        return voiceSocket != null ? voiceSocket.getLocalPort() : VOICE_PORT;
    }

    // 更新用户语音信息
    public static void updateUserIP(String username, String ipAddress, int port) {
        // 验证端口有效性
        if (port <= 0 || port > 65535) {
            System.err.println("忽略无效端口更新: " + username + " -> " + port);
            return;
        }

        // 验证IP地址有效性
        if (ipAddress == null || ipAddress.isEmpty()) {
            System.err.println("忽略无效IP地址: " + username);
            return;
        }

        // 如果是本地地址，转换为实际IP
        if (ipAddress.equals("127.0.0.1") || ipAddress.equals("localhost")) {
            try {
                ipAddress = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                System.err.println("无法获取本地IP地址: " + e.getMessage());
                return;
            }
        }

        UserVoiceInfo info = userInfoMap.get(username);
        if (info == null) {
            info = new UserVoiceInfo(ipAddress, port);
            userInfoMap.put(username, info);
            System.out.println("新增用户语音信息: " + username + " -> " + ipAddress + ":" + port);
        } else {
            // 只有当新端口有效时才更新
            info.ipAddress = ipAddress;
            info.voicePort = port;
            System.out.println("更新用户语音信息: " + username + " -> " + ipAddress + ":" + port);
        }
    }

    // 开始一对一语音聊天
    // 修改 startVoiceChat 方法
    public static boolean startVoiceChat(String targetUser) {
        if (currentVoiceParticipants.containsKey(targetUser)) {
            System.err.println("已经在与 " + targetUser + " 进行语音聊天");
            return false;
        }

        UserVoiceInfo targetInfo = userInfoMap.get(targetUser);
        if (targetInfo == null) {
            System.err.println("无法获取目标用户语音信息: " + targetUser);
            return false;
        }

        // 验证端口有效性
        if (targetInfo.voicePort <= 0 || targetInfo.voicePort > 65535) {
            System.err.println("目标端口无效，等待更新: " + targetUser + ":" + targetInfo.voicePort);
            return false;
        }

        System.out.println("准备连接到 " + targetUser + " 最新地址: " +
                targetInfo.ipAddress + ":" + targetInfo.voicePort);

        // 添加到当前参与者
        currentVoiceParticipants.put(targetUser, targetInfo.voicePort);

        // 启动音频设备
        startAudioDevices();

        // 发送测试数据包验证连接
        try {
            byte[] testData = "TEST".getBytes();
            DatagramPacket testPacket = new DatagramPacket(
                    testData, testData.length,
                    InetAddress.getByName(targetInfo.ipAddress), targetInfo.voicePort);
            voiceSocket.send(testPacket);
            System.out.println("已发送测试数据包到 " + targetUser);

            return true;
        } catch (Exception e) {
            System.err.println("连接测试失败: " + e.getMessage());
            currentVoiceParticipants.remove(targetUser);
            return false;
        }
    }

    // 创建会议房间
    public static String createConferenceRoom(String creator) {
        String roomId = UUID.randomUUID().toString().substring(0, 8);
        Set<String> participants = ConcurrentHashMap.newKeySet();
        participants.add(creator);
        conferenceRooms.put(roomId, participants);
        return roomId;
    }

    // 加入会议房间
    public static boolean joinConferenceRoom(String roomId, String username) {
        Set<String> participants = conferenceRooms.get(roomId);
        if (participants != null) {
            participants.add(username);

            // 添加所有参与者到当前语音会话(除了自己)
            for (String participant : participants) {
                if (!participant.equals(username)) {
                    UserVoiceInfo info = userInfoMap.get(participant);
                    if (info != null) {
                        currentVoiceParticipants.put(participant, info.voicePort);
                    }
                }
            }

            startAudioDevices();
            return true;
        }
        return false;
    }

    // 启动音频设备
    private static void startAudioDevices() {
        try {
            if (microphone == null || !microphone.isOpen()) {
                DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
                microphone = (TargetDataLine) AudioSystem.getLine(info);
                microphone.open(audioFormat);
                microphone.start();

                // 启动发送线程
                new Thread(() -> {
                    byte[] buffer = new byte[BUFFER_SIZE];
                    while (!currentVoiceParticipants.isEmpty()) {
                        int bytesRead = microphone.read(buffer, 0, buffer.length);
                        if (bytesRead > 0) {
                            sendVoiceData(buffer, bytesRead);
                        }
                    }
                    microphone.close();
                    microphone = null;
                }).start();
            }

            if (speakers == null || !speakers.isOpen()) {
                DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
                speakers = (SourceDataLine) AudioSystem.getLine(info);
                speakers.open(audioFormat);
                speakers.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 发送语音数据
    private static void sendVoiceData(byte[] data, int length) {
        if (voiceSocket == null || voiceSocket.isClosed()) {
            System.err.println("语音套接字未初始化或已关闭");
            return;
        }

        for (Map.Entry<String, Integer> entry : currentVoiceParticipants.entrySet()) {
            String username = entry.getKey();
            int port = entry.getValue();
            UserVoiceInfo info = userInfoMap.get(username);

            if (info != null && port > 0 && port <= 65535) {
                try {
                    InetAddress address = InetAddress.getByName(info.ipAddress);
                    DatagramPacket packet = new DatagramPacket(data, length, address, port);
                    voiceSocket.send(packet);
                    System.out.println("成功发送语音数据到 " + username + ":" + port);
                } catch (Exception e) {
                    System.err.println("发送语音数据到 " + username + " 失败: " + e.getMessage());
                }
            } else {
                System.err.println("无效的目标用户信息或端口: " + username + ":" + port);
            }
        }
    }

    // 接收语音数据
    private static void receiveVoice() {
        byte[] buffer = new byte[BUFFER_SIZE * 2];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            try {
                if (voiceSocket == null || voiceSocket.isClosed()) {
                    System.err.println("语音套接字已关闭，停止接收");
                    break;
                }

                voiceSocket.receive(packet);
                System.out.println("收到语音数据包，来自: " + packet.getAddress() +
                        ":" + packet.getPort() +
                        "，大小: " + packet.getLength() + "字节");

                //String senderIP = packet.getAddress().getHostAddress();
                //int senderPort = packet.getPort();

                // 处理测试包
                if (packet.getLength() == 4 && new String(packet.getData(), 0, 4).equals("TEST")) {
                    System.out.println("收到测试包，来自: " + packet.getAddress() + ":" + packet.getPort());

                    // 查找发送者用户名并更新其端口信息
                    String senderIP = packet.getAddress().getHostAddress();
                    int senderPort = packet.getPort();

                    // 遍历用户信息，找到匹配IP的用户
                    for (Map.Entry<String, UserVoiceInfo> entry : userInfoMap.entrySet()) {
                        if (entry.getValue().ipAddress.equals(senderIP) ){
                            // 更新发送者的端口信息
                            updateUserPort(entry.getKey(), senderPort);
                            break;
                        }
                    }
                    continue;
                }

                // 检查是否是音频数据（长度大于4且不是"TEST"）
                if (packet.getLength() > 4 && !new String(packet.getData(), 0, 4).equals("TEST")) {
                    if (speakers != null && speakers.isOpen()) {
                        System.out.println("准备播放音频数据，扬声器状态: " +
                                speakers.isOpen() + ", " +
                                speakers.isActive());

                        speakers.write(packet.getData(), packet.getOffset(), packet.getLength());
                        System.out.println("已播放音频数据");
                    } else {
                        System.err.println("扬声器未初始化或已关闭");
                    }
                }
            } catch (SocketTimeoutException e) {
                // 正常超时，继续等待
                continue;
            } catch (IOException e) {
                System.err.println("语音接收错误: " + e.getMessage());
                if (voiceSocket.isClosed()) {
                    break;
                }
            }
        }
    }

    // 结束语音聊天
    public static void endVoiceChat() {
        currentVoiceParticipants.clear();
        stopAudioDevices();
    }

    // 停止音频设备
    private static void stopAudioDevices() {
        if (microphone != null) {
            microphone.stop();
            microphone.close();
            microphone = null;
        }
        if (speakers != null) {
            speakers.stop();
            speakers.close();
            speakers = null;
        }
    }

    // 用户下线时清理
    public static void cleanup(String username) {
        userInfoMap.remove(username);
        currentVoiceParticipants.remove(username);

        // 从所有会议房间中移除
        for (Set<String> participants : conferenceRooms.values()) {
            participants.remove(username);
        }

        if (currentVoiceParticipants.isEmpty()) {
            stopAudioDevices();
        }
    }

    // 在VoiceChatManager类中添加
    public static boolean hasUserInfo(String username) {
        return userInfoMap.containsKey(username) &&
                userInfoMap.get(username).voicePort > 0 &&
                userInfoMap.get(username).ipAddress != null;
    }

    public static void updateUserPort(String username, int newPort) {
        if (newPort <= 0 || newPort > 65535) {
            System.err.println("拒绝无效端口更新: " + username + " -> " + newPort);
            return;
        }

        UserVoiceInfo info = userInfoMap.get(username);
        if (info != null) {
            System.out.println("更新用户端口: " + username + " " + info.voicePort + " -> " + newPort);
            info.voicePort = newPort;

            // 更新当前会话中的端口
            if (currentVoiceParticipants.containsKey(username)) {
                currentVoiceParticipants.put(username, newPort);
            }
        }
    }
    // 添加检查是否是自己的数据包的方法
    private static boolean isSelfPacket(String ip, int port) {
        try {
            String localIP = InetAddress.getLocalHost().getHostAddress();
            int localPort = voiceSocket.getLocalPort();
            return ip.equals(localIP) && port == localPort;
        } catch (Exception e) {
            return false;
        }
    }


}